package library.multiple_pictures_selector.utils;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Rect;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;

/**
 * Created by Ricky on 2018/4/12.
 */
public class EffectiveBitmapUtils {
    /**
     * default quality(0~100)
     */
    private static int DEFAULT_QUALITY = 30;

    /**
     * compress by quality
     *
     * @param bitmap bitmap
     * @param file   Target file
     */
    public static void compressByQuality(Bitmap bitmap, File file) {
        int options = DEFAULT_QUALITY;
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        bitmap.compress(Bitmap.CompressFormat.JPEG, options, byteArrayOutputStream);
        try {
            FileOutputStream fos = new FileOutputStream(file);
            fos.write(byteArrayOutputStream.toByteArray());
            fos.flush();
            fos.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * compress by quality
     *
     * @param bitmap  bitmap
     * @param file    Target file
     * @param quality quality
     */
    public static void compressByQuality(Bitmap bitmap, File file, int quality) {
        if (quality <= 0) {
            // default value
            quality = DEFAULT_QUALITY;
        }
        int options = quality;
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        bitmap.compress(Bitmap.CompressFormat.JPEG, options, byteArrayOutputStream);
        try {
            FileOutputStream fos = new FileOutputStream(file);
            fos.write(byteArrayOutputStream.toByteArray());
            fos.flush();
            fos.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * compress by size(按长宽比例压缩)
     *
     * @param bitmap bitmap
     * @param file   Target file
     * @param ratio  ratio
     */
    public static void compressBySize(Bitmap bitmap, File file, int ratio) {
        if (ratio <= 0) {
            // default value
            ratio = 8;
        }
        // empty bitmap
        Bitmap result = Bitmap.createBitmap(bitmap.getWidth() / ratio, bitmap.getHeight() / ratio, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(result);
        Rect rect = new Rect(0, 0, bitmap.getWidth() / ratio, bitmap.getHeight() / ratio);
        canvas.drawBitmap(bitmap, null, rect, null);

        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        result.compress(Bitmap.CompressFormat.JPEG, 100, byteArrayOutputStream);
        try {
            FileOutputStream fos = new FileOutputStream(file);
            fos.write(byteArrayOutputStream.toByteArray());
            fos.flush();
            fos.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * compress by sample
     *
     * @param filePath          source file
     * @param file              Target file
     * @param inSampleSize      sample size
     * @param inPreferredConfig Bitmap.Config
     */
    public static void compressBySample(String filePath, File file, int inSampleSize, Bitmap.Config inPreferredConfig) {
        if (inSampleSize <= 0) {
            // default value
            inSampleSize = 8;
        }
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = false;
        options.inSampleSize = inSampleSize;
        options.inPreferredConfig = inPreferredConfig;
        Bitmap bitmap = BitmapFactory.decodeFile(filePath, options);

        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        bitmap.compress(Bitmap.CompressFormat.JPEG, 100, byteArrayOutputStream);
        try {
            if (!file.exists()) {
                if (!file.createNewFile()) {
                    return;
                }
            }
            FileOutputStream fos = new FileOutputStream(file);
            fos.write(byteArrayOutputStream.toByteArray());
            fos.flush();
            fos.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * Firstly compress by simple size and secondly compress by quality
     *
     * @param sourceFile    sourceFile
     * @param targetFile    targetFile
     * @param targetWidth   targetWidth
     * @param targetHeight  targetHeight
     * @param targetQuality targetQuality
     */
    public static void compressBySimpleAndQuality(
            String sourceFile, File targetFile, int targetWidth, int targetHeight, int targetQuality) {
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(sourceFile, options);
        options.inJustDecodeBounds = false;
        options.inSampleSize = EffectiveBitmapUtils.calculateInSampleSize(options, targetWidth, targetHeight);
        options.inJustDecodeBounds = false;
        options.inPreferredConfig = Bitmap.Config.RGB_565;
        Bitmap bitmap = BitmapFactory.decodeFile(sourceFile, options);

        compressByQuality(bitmap, targetFile, targetQuality);
    }

    /**
     * calculate inSampleSize by request width and height
     *
     * @param options   BitmapFactory.Options
     * @param reqWidth  request width
     * @param reqHeight request height
     * @return int
     */
    public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
        // Raw height and width of image
        final int height = options.outHeight;
        final int width = options.outWidth;
        int inSampleSize = 1;
        if (height > reqHeight || width > reqWidth) {
            // Calculate ratios of height and width to requested height and width,计算出实际宽高和目标宽高的比率
            final int heightRatio = Math.round((float) height / (float) reqHeight);
            // 选择宽和高中最小的比率作为inSampleSize的值，这样可以保证最终图片的宽和高一定都会大于等于目标的宽和高。
            final int widthRatio = Math.round((float) width / (float) reqWidth);
            inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
            // Anything more than 2x the requested pixels we'll sample down
            final float totalPixels = width * height;
            // further
            final float totalReqPixelsCap = reqWidth * reqHeight * 2;
            while (totalPixels / (inSampleSize * inSampleSize) > totalReqPixelsCap) {
                inSampleSize++;
            }
        }
        return inSampleSize;
    }
}
